package api

import (
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"net/http"
	"regexp"
	"strings"
	"time"
	. "xm_shop/database"
	. "xm_shop/models"
	. "xm_shop/utils"
)

type PassController struct{}

// 获取图形验证码
func (p PassController) Captcha(context *gin.Context) {
	id, b64s, _, err := MakeCaptcha(50, 120, 4)
	if err != nil {
		context.String(http.StatusBadRequest, "获取验证码失败")
		return
	}
	context.JSON(http.StatusOK, gin.H{
		"success":      true,
		"captchaId":    id,
		"captchaImage": b64s,
	})
}

// 发送短信验证码(接入注册)
func (p PassController) SendCode(context *gin.Context) {
	phone := context.Query("phone")
	verifyCode := context.Query("verify_code")
	captchaId := context.Query("captcha_id")
	if captchaId == "resend" { // 第二个注册页面发送的验证码
		session := sessions.Default(context)
		sessionVerifyCode := session.Get("verifyCode")
		sessionVerifyCodeStr, ok := sessionVerifyCode.(string)
		if !ok || sessionVerifyCodeStr != verifyCode {
			context.String(http.StatusBadRequest, "验证码有误")
			return
		}
	} else {
		// 1. 图形验证码是否合法
		if flag := VerifyCaptcha(captchaId, verifyCode); !flag {
			context.String(http.StatusBadRequest, "验证码错误")
			return
		}
		// 保存图形验证码
		session := sessions.Default(context)
		session.Set("verifyCode", verifyCode)
		session.Save()
	}
	// 2. 验证手机格式是否合法
	pattern := `^1[3|4|5|6|7|8|9]\d{9}$` // 编写正则
	reg := regexp.MustCompile(pattern)   // 创建正则对象
	if !reg.MatchString(phone) {
		context.String(http.StatusBadRequest, "手机号格式不合法")
		return
	}
	// 3. 验证手机号是否注册过
	var user User
	DB.Where("phone = ?", phone).Take(user)
	if user.ID != 0 {
		context.String(http.StatusBadRequest, "手机号已注册, 请直接登录")
		return
	}
	// 4. 当前Ip今天发送短信的次数
	currentDay := time.Now().Format("20060102") // 获取当前时间
	ip := context.ClientIP()                    // 客户端的ip
	var sendCount int64
	DB.Table("user_temp").Where("ip = ? AND add_day = ?", ip, currentDay).Count(&sendCount)
	if sendCount > 10 { // 设置10次上线
		context.String(http.StatusBadRequest, "ip发送次数上限")
		return
	}
	//5. 当前手机号今天发送次数
	var userTemp UserTemp
	// 生成随机验证码
	smsCode := GetRandomNum()
	// 生成签名
	sign := Md5(phone + currentDay)
	DB.Where("phone = ? AND add_day = ?", phone, currentDay).Take(&userTemp)
	if userTemp.ID != 0 { // 当前手机号今天发送了短信
		if userTemp.SendCount > 3 {
			context.String(http.StatusBadRequest, "当前手机号发送次数上限")
			return
		} else {
			// 1. 发送短信验证码

			// 2. 采用session保存验证码
			session := sessions.Default(context)
			session.Set("smsCode", smsCode)
			session.Save()

			// 3. 更新发送次数
			userTemp.SendCount += 1
			userTemp.AddTime = int(time.Now().Unix()) // 更新时间
			if err := DB.Save(&userTemp).Error; err != nil {
				context.String(http.StatusBadRequest, "数据修改失败")
				return
			}
		}
	} else { // 当前手机号今天没有发送短信, 创建一条新记录
		// 1. 发送短信验证码

		// 2. 服务器采用session保存数据
		session := sessions.Default(context)
		session.Set("smsCode", smsCode)
		session.Save()

		// 3. 记录发送短信的次数
		oneUserTemp := UserTemp{
			Ip:        ip,
			Phone:     phone,
			AddDay:    currentDay,
			SendCount: 1,
			AddTime:   int(time.Now().Unix()),
			Sign:      sign,
		}
		if err1 := DB.Create(&oneUserTemp).Error; err1 != nil {
			context.String(http.StatusBadRequest, "短信记录生成失败")
			return
		}
	}
	context.JSON(http.StatusOK, gin.H{
		"success": true,
		"message": "短信发送成功",
		"sign":    sign,
	})
}

// 验证短信验证码
func (p PassController) ValidateSmsCode(context *gin.Context) {
	sign := context.Query("sign")
	smsCode := context.Query("sms_code")
	// 1. 验证数据是否合法
	var userTemp UserTemp
	DB.Where("sign = ?", sign).Take(&userTemp)
	if userTemp.ID == 0 {
		context.String(http.StatusBadRequest, "数据不合法")
		return
	}
	// 2. 验证短信验证码是否正确
	session := sessions.Default(context)
	sessionSmsCode := session.Get("smsCode")
	sessionSmsCodeStr, ok := sessionSmsCode.(string)
	if !ok || sessionSmsCodeStr != smsCode {
		context.String(http.StatusBadRequest, "验证码不正确")
		return
	}
	// 3. 判断短信验证码是否过期
	nowTime := time.Now().Unix()
	if (nowTime - int64(userTemp.AddTime)/60) > 15 {
		context.String(http.StatusBadRequest, "验证码过期")
		return
	}
	context.String(http.StatusOK, "检验成功")
}

// 执行用户登录
func (p PassController) Login(context *gin.Context) {
	phone := strings.Trim(context.PostForm("phone"), " ")
	password := strings.Trim(context.PostForm("password"), " ")
	captchaId := context.PostForm("captcha_id")
	captchaVal := context.PostForm("captcha_val")
	// 1. 验证图形验证码是否正确
	if flag := VerifyCaptcha(captchaId, captchaVal); !flag {
		context.String(http.StatusBadRequest, "图形验证码错误")
		return
	}
	// 2. 验证用户名密码是否正确
	password = Md5(password)
	var user User
	DB.Where("phone = ? AND password = ?", phone, password).Where(&user)
	if user.ID == 0 {
		context.String(http.StatusBadRequest, "密码错误")
		return
	}
	// 执行登录
	Cookie.Set(context, "userInfo", user)
	context.String(http.StatusOK, "登录成功")
}

func (p PassController) RegisterStep1(context *gin.Context) {

}

func (p PassController) RegisterStep2(context *gin.Context) {
	// 1. 获取sign, 判断sign是否合法
	sign := context.Query("sign")
	verifyCode := context.Query("verify_code")

	// 1. 验证图形验证码是否正确
	session := sessions.Default(context)
	sessionVerifyCode := session.Get("verifyCode")
	sessionVerifyCodeStr, ok := sessionVerifyCode.(string) // 断言
	if !ok || verifyCode != sessionVerifyCodeStr {
		context.String(http.StatusBadRequest, "数据不合法")
		return
	}

	var userTemp UserTemp
	DB.Where("sign = ?", sign).Take(&userTemp)
	if userTemp.ID == 0 {
		context.String(http.StatusBadRequest, "签名不合法")
		return
	}
	context.JSON(http.StatusOK, gin.H{
		"success":    true,
		"phone":      userTemp.Phone,
		"verifyCode": verifyCode,
		"sign":       sign,
	})
}

func (p PassController) RegisterStep3(context *gin.Context) {
	sign := context.Query("sign")
	smsCode := context.Query("sms_code")
	// 1. 判断短信验证码是否正确
	session := sessions.Default(context)
	sessionSmsCode := session.Get("smsCode")
	sessionSmsCodeStr, ok := sessionSmsCode.(string)
	if !ok || sessionSmsCodeStr != smsCode {
		context.String(http.StatusBadRequest, "验证码错误")
		return
	}
	// 2. 判断签名是否正确
	var userTemp UserTemp
	DB.Where("sign = ?", sign).Take(&userTemp)
	if userTemp.ID == 0 {
		context.String(http.StatusBadRequest, "签名出错")
		return
	}
	context.JSON(http.StatusOK, gin.H{
		"phone":   userTemp.Phone,
		"smsCode": smsCode,
		"sign":    sign,
	})
}

// 执行注册
func (p PassController) DoRegister(context *gin.Context) {
	// 1. 获取表单数据
	sign := context.PostForm("sign")
	smsCode := context.PostForm("sms_code")
	password := context.PostForm("password")
	rpassword := context.PostForm("rpassword")
	// 2. 验证smsCode是否合法
	session := sessions.Default(context)
	sessionSmsCode := session.Get("smsCode")
	sessionSmsCodeStr, ok := sessionSmsCode.(string)
	if !ok || sessionSmsCodeStr != smsCode {
		context.String(http.StatusBadRequest, "非法请求")
		return
	}
	// 3. 验证签名是否合法
	var userTemp UserTemp
	DB.Where("sign = ?", sign).Take(&userTemp)
	if userTemp.ID == 0 {
		context.String(http.StatusBadRequest, "签名失效")
		return
	}
	// 4. 验证密码是否合法
	if len(password) < 6 || password != rpassword {
		context.String(http.StatusBadRequest, "密码不合法")
		return
	}
	// 5. 完成注册
	user := User{
		Phone:    userTemp.Phone,
		Password: Md5(password),
		LastIp:   context.ClientIP(),
		AddTime:  int(time.Now().Unix()),
		Status:   1,
	}
	if err1 := DB.Create(&user).Error; err1 != nil {
		context.String(http.StatusBadRequest, "数据创建失败")
		return
	}

	// 6. 执行登录
	Cookie.Set(context, "userInfo", user)
	context.String(http.StatusOK, "注册成功")
}

// 退出登录
func (p PassController) Logout(context *gin.Context) {
	Cookie.Remove(context, "userInfo")

	//context.Request.Referer() // 可以跳转到上一个页面
	context.String(http.StatusOK, "登出成功")
}
